home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * @(#)msgCode.c 1.6 2/23/90
- */
-
- /* COPYRIGHT NOTICE:
- * Copyright 1986 Eric Jul. May not be used for any
- * purpose without written permission from the author.
- * Certain portions have been derived from Eden code.
- *
- * These routines implement the message level of the
- * Message Module. It creates, manipulates, and destroys messages.
- * It provides a partially flow controlled data link
- * point-to-point transmission to other Eden hosts.
- * A reliable pipeline protocol is used.
- * Retransmission and piggybacked acknowledgements.
- *
- * Timeout values need tuning
- * Message timeout is primitive as to improve performance.
- * The variable HOTS is global within this module. It references
- * the current logical node being talked to - if any.
- * The primitive hack to handle NOHOTSENTRY situations should be fixed.
- */
-
-
- extern void ErrMsg();
- #ifdef xkernel
- #include <sys/types.h>
- #include "userupi.h"
- #include "userprocess.h"
- #include "ip.h"
- #include "udp.h"
- #include "debug.h"
-
- static IPaddr myipaddr;
- #else
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sys/ioctl.h>
- #include <netdb.h>
- extern errno;
- #endif
-
- extern char *inet_ntoa();
- #undef integer
-
- #include "Kernel/h/system.h"
- #include "Kernel/h/assert.h"
- #include "Kernel/h/macros.h"
- #include "Kernel/h/mmTypes.h"
- #include "Kernel/h/mmCodes.h"
- #include "Kernel/h/unixCodes.h"
- #include "Kernel/h/mmBufTypes.h"
- #include "Kernel/h/mmFifoTypes.h"
- #include "Kernel/h/mmMsgDefs.h"
- #include "Kernel/h/mmMsgTypes.h"
- #include "Kernel/h/mmEthrTypes.h"
- #include "Kernel/h/hotsTypes.h"
- #include "Kernel/h/kEvents.h"
- #include "Kernel/h/timerTypes.h"
- #include "Kernel/h/kmdTypes.h"
- #include "Kernel/h/sigio.h"
-
- /*++BRDADDR++*/
- #include <net/if.h>
- /*--BRDADDR--*/
-
-
- #define endcase break
-
- extern int DisplayEdenMsg(),
- GetEdenMsg(),
- PutEdenMsg();
-
- extern void KMDInterrupt();
- extern void QueueTask();
- extern void SISetSockHandler();
- extern time_t nodeIncarnationId;
-
- /* Forward */
- HResult MMReceiveEtherHandler();
- void MMInitHOTSEntry(), MMStats(), EtherStats();
- static KKStatus SendFrame();
-
- /************************************************************/
- /* Static Global Variables */
- /************************************************************/
-
- NodeNum MMLocalLNN = 0;
- EdenPort MMNetPort = NULLEDENPORT;
- MessageId MMNextMsgId = FIRSTMSGID;
-
- Boolean HasNetPort = False; /* Set by MMInitMsgModule. */
-
- #ifdef BSD
- int MMEtherFile = -1;
- #else
- #ifdef xkernel
- SESSN MMEtherSessn = ERR_SESSN;
- PROTL MMEtherProtl = ERR_PROTL;
-
- #define EMXSEND(ses,par,pak,siz,bytes) {\
- (ses) = xopen(MMEtherProtl,UDP,(par));\
- (bytes) = xpush((ses), (pak), (siz));\
- }
-
-
- #endif
- #endif
- EtherNetAddress MMLocalEtherNet = {0}; /* All zeros, believe it or not */
- EtherNetAddress MMBroadcastAddr;
- unsigned short MMBroadcastPort;
- char vMMEtherDevName[100] = "";
-
- #ifdef xkernel
- /******************
- xkernel handlers
- ******************/
- /*ARGSUSED*/
- MMdemux_handler(s, msg, len)
- SESSN s;
- register char *msg;
- int len;
- {
- MessagePtr newmsg;
- KKStatus status;
-
- xkhandlerstart();
- DebugMsg(4, "MMdemux_handler, len = %d\n", len);
- /* trivially does what SIGIO handler used to do (less socket reads) */
- status = MMAllocateMsg( MAXMESSAGESIZE, &newmsg);
- if(mSUCCESS(status)) {
- bcopy(msg,(char *)newmsg,len);
- HoldSigs();
- QueueTask( (HandlerPtr)MMReceiveEtherHandler, (char *)newmsg);
- ReleaseSigs();
- } else ErrMsg(">> MMdemux_handler got no buffer 0x%02x\n", status);
- xkhandlerend();
- }
- MMopendone_handler()
- {
- xkhandlerstart();
- DebugMsg(3, "MMopendone_handler\n");
- xkhandlerend();
- }
- MMclosedone_handler()
- {
- xkhandlerstart();
- xkhandlerend();
- }
- #endif
-
- /* Protocol administration definitions.
- * Most of the following are local constants, but have been defined as
- * global variables, so that tuning of the protocol may be done by
- * adjusting these variable, e.g., at boot time, or even dynamically.
- * The global variables have been named something with "MM" and have
- * prefixed with "v". Variables prefixed by "c" may be inspected only.
- * Notes:
- * The vMM* variables may be reset by changing their value via the KMD
- * 'changevar' procedure, or by setting their new values in the
- * local 'kernelrc' file, or the '/usr/em/emrc' file.
- * Restrictions:
- * vMMSendWindow > 0 -- Else protocol Invalid
- * 2*vMMSendWindow + 1 < SEQRANGE -- Else protocol Invalid
- * vMMACKTimeout < vMMMsgTimeout -- Else too many retransmits & NAKs.
- * vMMACKTimeout > 1 -- Since one tick may expire immediately.
- * vMMMsgTimeout > 1
- * Preferences:
- * vMMACKTimeout < vMMMsgTimeout - 1
- * -- Else risk too close.
- * vMMForceAck > 1 -- Else ACK for every msg.
- * vMMForceAck <= vMMSendWindow+1 -- Else No Forced ACK ever. (Can be
- * -- used to turn it off.)
- * vMMForceAck < vMMSendWindow -- To prevent a high-volume sender
- * -- from blocking due to window full.
- */
-
- #define MAXSEQNO 255 /* Must fit into a byte. */
- #define SEQRANGE 256 /* MAXSEQNO + 1 */
-
- #define MAXSWSIZE 4 /* Max size of Send window. */
- int vMMSendWindow = MAXSWSIZE; /* must be < (MAXSEQNO - 1)/2 */
- #define FORCEACK 3 /* # of unACKed msg to force ACK */
- int vMMForceAck = FORCEACK;
- #define TICKSIZE 1000000 /* microseconds per tick */
- int vMMTickSize = TICKSIZE;
- #define MSGTIMEOUTCOUNT 6 /* Tick count for msg timeout */
- int vMMMsgTimeout = MSGTIMEOUTCOUNT;
- #define ACKTIMEOUTCOUNT 2 /* Tick count for ACK timeout */
- int vMMACKTimeout = ACKTIMEOUTCOUNT;
- #define RETRANSCOUNT 100 /* For declaring nodes dead*/
- int vMMBigRetransCount
- = RETRANSCOUNT;
-
- /************ Statistical variables ************/
- /* For statistical use only */
- long cMMOutOfOrderCount = 0;
- long cMMRetransCount = 0;
- long cMMNAKsSentCount = 0;
- long cMMNAKsRecvCount = 0;
- long cMMMsgDroppedCount = 0;
- long cMMACKsSentCount = 0;
- long cMMACKsRecvCount = 0;
- long cMMMsgDeliveredCount = 0;
- long cMMMsgAcceptedCount = 0;
- long cMMMsgSentSynchRawCount = 0;
- long cMMBroadcastHOSTCount = 0;
- long cMMMulticastCount = 0;
- long cMMBcastDefaultCount = 0;
- long cMMFirstFCMsgCount = 0;
- long cMMEtherPacketSentCount = 0;
- long cMMAccumPacketSize = 0;
- long cMMNormalInterruptCount = 0;
- long cMMEmergencyIntCount = 0;
- long cMMEthernetIntCount = 0;
- long cMMMsgAllocCount = 0;
- long cMMMsgDeAllocCount = 0;
- long cMMMsgSentSynchCount = 0;
- long cMMMsgSentRawCount = 0;
- long cMMMsgSentCount = 0;
- long cMMAccumMsgSize = 0; /* Divide by cMMMsgSentCount */
-
- /************ End of Statistical Variables ************/
-
-
- /************************************************************/
- /* Static Local Variables */
- /************************************************************/
-
- #define NxtSeq(X) (X == MAXSEQNO ? 0 : X + 1)
- #define PrvSeq(X) (X == 0 ? MAXSEQNO : X - 1)
- #define IncSeq(X) if (X++ == MAXSEQNO) X=0
-
-
- /* Local variables */
-
- static HOTSRecord *HOTS;
- static HOTSRecord defaultHOTS; /* Used when only a single HOTS entry is
- * needed, rather than a full HOTS table
- * (saves allocating a full table and
- * linking in unneeded HOTS table
- * manipulation routines)
- */
-
- static Boolean TimerActive;
- static HOTSRecord THead;
- static EnetPacket SNpacket;
-
- #define TextSize 100
- char ErrorText[TextSize];
-
-
- /************************************************************/
- /* Local Subroutines */
- /************************************************************/
-
-
-
- #define between(a,b,c) (a<=b && b<c || c<a && a<=b || b<c && c<a)
-
- #define CheckTimer \
- if (! HOTS->Timed) { \
- /* Start timing of this logical node: Insert in timer list.*/ \
- MXTraceMsg(5, "Timeout queue insert lnn = %d\n", HOTS->LNN); \
- HOTS->TNext = THead.TNext; \
- HOTS->TPrev = &THead; \
- (THead.TNext)->TPrev = HOTS; \
- THead.TNext = HOTS; \
- HOTS->Timed = TRUE; \
- /* Start the timeout handler if is not already active. */ \
- if (!TimerActive) { \
- MXTraceMsg(5, "Start timer Q on LNN = %d\n", MMLocalLNN); \
- TimerActive = TRUE; \
- (void) MMSetMicroTimer((int) (vMMTickSize/1000000), \
- (int) (vMMTickSize%1000000), (HandlerPtr) TimeoutHandler, \
- NULL, (TimerId *) NULL); \
- } \
- };
-
-
-
- /*************************************************************************
- * Upcall Routines. These routines allow higher level routines to *
- * associate handlers with specific events that arise in the low *
- * level message module routines. This has 2 purposes: first, *
- * it insulates the HOTS table representation from the message *
- * module; second, it allows the message module to be used in *
- * programs that don't access the HOTS table (such the message *
- * module test program). Included in this set of routines are the *
- * default routines (which simply announce when they are called) *
- * and a routine to allow reassociation of routines with events. *
- *************************************************************************/
-
- static KKStatus MMDefaultHOTSSearchPtrHandler(fQueryLNN, fEntryPtr)
- NodeNum fQueryLNN;
- HOTSRecord **fEntryPtr;
- {
- MXTraceMsg(5, "MMDefaultHOTSSearchPtrHandler: fQueryLNN = %d\n", fQueryLNN);
- if (defaultHOTS.LNN == (NodeNum) 0){
- /* defaultHOTS hasn't been setup. Note: this check assumes that
- LNN 0 is never used as a real Kernel or POD */
- return(MMSF_DefaultHOTSNotInitialized);
- } else {
- (*fEntryPtr) = &defaultHOTS; /* Return the single default HOTS record
- from the message module */
- MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: &defaultHOTS = 0x%05x\n",
- &defaultHOTS);
- MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.LNN = %d;\n",
- defaultHOTS.LNN);
- MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: EthAdr in defaultHOTS.EtherAddr = %s.\n", inet_ntoa(defaultHOTS.EtherAddr.sin_addr));
- MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.EtherAddr.sin_port = %d\n",
- ntohs(defaultHOTS.EtherAddr.sin_port));
- MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.NodeStat = %d\n",
- defaultHOTS.NodeStat);
- return(MMSS_Success);
- }
- }
-
- void MMSetupDefaultHOTSEntry(fHOTSEntry)
- HOTSRecord fHOTSEntry;
- {
- MXTraceMsg(4, "MMSetupDefaultHOTSEntry: fHOTSEntry.LNN = %d\n",
- fHOTSEntry.LNN);
- MXTraceMsg(4,
- "MMSetupDefaultHOTSEntry: fHOTSEntry.EtherAddr = %s, port = %d\n",
- inet_ntoa(fHOTSEntry.EtherAddr.sin_addr),
- ntohs(fHOTSEntry.EtherAddr.sin_port));
- MXTraceMsg(4, "MMSetupDefaultHOTSEntry: fHOTSEntry.NodeStat = %d\n",
- fHOTSEntry.NodeStat);
- defaultHOTS = fHOTSEntry; /* Copy the passed HOTS entry into the MM
- global variable defaultHOTS */
- /* Now DO NOT forget to initialize protocol stuff */
- MMInitHOTSEntry(&defaultHOTS);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultBigRetransCountHandler(fHOTSRec)
- HOTSRecord *fHOTSRec;
- {
- MXTraceMsg(1, "MMDefaultBigRetransCountHandler was called\n");
- return(MMSS_Success);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultEdenPortDeathHandler(fPort)
- EdenPort fPort;
- {
- MXTraceMsg(4, "MMDefaultEdenPortDeathHandler: Port = %d\n", fPort);
- return(MMSS_Success);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultNoHOTSEntryHandler(fMsg)
- MessagePtr fMsg;
- {
- /* The default action for a missing HOTS entry is to do nothing */
- MXTraceMsg(4, "MMDefaultNoHOTSEntryHandler: LNN = %d\n",
- fMsg->MsgHdr.MsgSrc);
- return(MMSF_NoHOTSEntry);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultSendWindowFullHandler(fHOTSRec)
- HOTSRecord *fHOTSRec;
- {
- /* The default action for send window full is to do nothing */
- MXTraceMsg(5, "MMDefaultSendWindowFullHandler was called\n");
- return(MMSS_Success);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultSendWindowNotFullHandler(fHOTSRec)
- HOTSRecord *fHOTSRec;
- {
- /* The default action for send window not full is to do nothing */
- MXTraceMsg(5, "MMDefaultSendWindowNotFullHandler was called\n");
- return(MMSS_Success);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultFirstFCMsgReceivedHandler(fHOTSRec, fMsg)
- HOTSRecord *fHOTSRec;
- MessagePtr fMsg;
- {
- /* The default action for first flow controlled msg received from the LNN
- associated with fHOTSRec is to do nothing */
- MXTraceMsg(4, "MMDefaultFirstFCMsgReceivedHandler was called, LNN %d\n",
- fHOTSRec->LNN);
- return(MMSS_Success);
- }
-
- /*ARGSUSED*/
- static KKStatus MMDefaultCheckMsgHandler(fMsg, fEntryPtr)
- MessagePtr fMsg;
- HOTSRecord **fEntryPtr;
- {
- MXTraceMsg(6, "MMDefaultCheckMsgHandler called.\n");
- return(MMDefaultHOTSSearchPtrHandler(0, fEntryPtr));
- }
- typedef KKStatus (*MMUpcallHandlerType) ();
-
- MMUpcallHandlerType MMUpcallHandler[NUMUPCALLEVENTS] = {
- MMDefaultHOTSSearchPtrHandler,
- MMDefaultBigRetransCountHandler,
- MMDefaultEdenPortDeathHandler,
- MMDefaultNoHOTSEntryHandler,
- MMDefaultSendWindowFullHandler,
- MMDefaultSendWindowNotFullHandler,
- MMDefaultFirstFCMsgReceivedHandler,
- MMDefaultCheckMsgHandler
- };
-
- KKStatus MMDefineUpcallHandler(fRoutine, fHandlerNumber)
- HandlerPtr fRoutine;
- int fHandlerNumber;
- {
- MXTraceMsg(4, "MMDefineUpcallHandler: fHandlerNumber = %d\n",
- fHandlerNumber);
- if (fHandlerNumber < 0 || fHandlerNumber >= NUMUPCALLEVENTS)
- return(MMSF_BadEventID);
- MMUpcallHandler[fHandlerNumber] = (MMUpcallHandlerType) fRoutine;
- return(MMSS_Success);
- }
-
- #ifdef DEFUNCT
- /* */
- /* Search the HOTS table for the LNN */
- /* */
-
- static KKStatus FindLNN( fLNN,
- fDestAddr
- )
- NodeNum fLNN;
- register DeviceAddr *fDestAddr;
- {
- HOTSRecord *info;
- KKStatus status;
-
- MXTraceMsg(5, "FindLNN( %d, %d )\n", fLNN, fDestAddr);
-
- /* Call higher level routine to search HOTS table */
- status = MMUpcallHandler[HOTSSEARCHPTR]( fLNN, &info );
-
- if ( ! mSUCCESS( status ) )
- return MMSF_BadNode;
- if ( info->NodeStat == Dead )
- return MMSF_NodeDown;
- status = MMSS_Success;
- fDestAddr->DevicePort = NULLEDENPORT;
- mEtherCopy( &(info->EtherAddr), &(fDestAddr->DeviceEnet) );
-
- MXTraceMsg(5, "end FindLNN( %d, %d )\n", (int)fDestAddr->DevicePort,
- (int) MachineAddress(fDestAddr->DeviceEnet));
-
- return status;
- }
-
- #endif DEFUNCT
-
- /**********************************************************************/
- /* MM snapshots defined for KMD use. */
- /* EtherStats(LNN) The Ethernet stats for communication */
- /* with the specified LNN */
- /* If LNN=0 then all MM EtherStats. */
- /* MMStats Dumps all MMStats */
- /**********************************************************************/
-
- void EtherStats(fLNN)
- int fLNN;
- {
- HOTSRecord *HOTSPtr;
- KKStatus status;
-
- if (fLNN == 0) { /* Print Etherstats in general. */
- KMDPrint("EtherNet statistics\n");
- KMDPrint("ReTran NAKSen NAKRcv MsgDrp ACKSen ACKRcv MsgDlv MsgAcp OutOrd\n%5d %6d %6d %6d %6d %6d %6d %6d %6d\n",
- cMMRetransCount,
- cMMNAKsSentCount, cMMNAKsRecvCount, cMMMsgDroppedCount,
- cMMACKsSentCount, cMMACKsRecvCount, cMMMsgDeliveredCount,
- cMMMsgAcceptedCount, cMMOutOfOrderCount);
- return;
- }
-
- /* Call higher level routine to search HOTS table */
- status = MMUpcallHandler[HOTSSEARCHPTR](fLNN, &HOTSPtr);
-
- if (! mSUCCESS(status) ) {
- KMDPrint("LNN not found in HOTS table - status 0x%02x\n", status);
- return;
- };
-
- KMDPrint("EtherNet Message Module statistics for LNN = %d\n", fLNN);
- KMDPrint("ReTran NAKSen NAKRcv MsgDrp ACKSen ACKRcv MsgDlv MsgAcp\n%5d %6d %6d %6d %6d %6d %6d %6d\n",
- HOTSPtr->RetransCount, HOTSPtr->NAKsSent, HOTSPtr->NAKsRecv,
- HOTSPtr->MsgDropped, HOTSPtr->ACKsSent, HOTSPtr->ACKsRecv,
- HOTSPtr->MsgDelivered, HOTSPtr->MsgAccepted);
- }
-
-
- void MMStats()
- {
- KMDPrint("Message Module statistics\n");
- EtherStats(0);
- KMDPrint("SynMsg SynRaw BcstPO Mulcst BcstDf FstFCM\n%5d %6d %6d %6d %6d %6d\n",
- cMMMsgSentSynchCount, cMMMsgSentSynchRawCount,
- cMMBroadcastHOSTCount, cMMMulticastCount,
- cMMBcastDefaultCount, cMMFirstFCMsgCount);
- KMDPrint("MsgAlloc MsgDeAll NormlInt EmergInt EtherInt\n%6d %8d %8d %8d %8d\n",
- cMMMsgAllocCount,
- cMMMsgDeAllocCount, cMMNormalInterruptCount,
- cMMEmergencyIntCount, cMMEthernetIntCount);
- KMDPrint("Total msg sent: %d Average size %d bytes.\n",
- cMMMsgSentCount, cMMAccumMsgSize
- / (cMMMsgSentCount ? cMMMsgSentCount : 1));
- return;
- }
-
- /***********************************************************************/
- /* Flow control protocol part. */
- /* Contains the routines which have been added to the message module */
- /* to support the flow control protocol for normal messages. */
- /* IMPORTANT NOTE: Most of these routines assume that the current */
- /* LNNs HOTS entry may be accessed via the pointer HOTS. */
- /* */
- /* See "Eden Reliable message passing in Eden. A Sliding Window */
- /* Protocol for Eden", Eric Jul, Eden Project, 84-02-19 */
- /***********************************************************************/
-
- /*Forward*/
- void SendSubNetPacket();
-
- void AckTimeout()
- {
- /* Ack Timer has expired; send a separate ack. */
- MXTraceMsg(3, "AckTimeout LNN %d, sending ACK for msg #%d\n",
- HOTS->LNN, HOTS->MsgExpected);
- HOTS->ACKsSent++; cMMACKsSentCount++;
- SendSubNetPacket(SNACK, (MessagePtr) NULL);
- }
-
-
- /***********************************************************************/
- void MsgTimeout()
- {
- FramePtr FP;
-
- /* Msg Timer has expired; Retransmit a packet. */
- MXTraceMsg(2, "MsgTimeout for LNN %d\n", HOTS->LNN);
- /* Assume (HOTS->SentPtr != NULL) is equivalent to (HOTS->SentPtr) */
- if ( HOTS->SentPtr ) {
- QueueRmv(HOTS->SentPtr, FP, Next);
- MXTraceMsg(2, "Retransmitting msg #%d for the %dth time\n",
- FP->packet.EnetData.MsgHdr.MsgSeq, (FP->RetransCount) + 1);
- HOTS->RetransCount++; cMMRetransCount++;
- QueueIns(HOTS->SentPtr, FP, Next);
- (void) SendFrame(FP);
-
- /* Now if the retransmit count is big inform upper levels
- by doing an upcall.
- */
- if (FP->RetransCount++ > vMMBigRetransCount) {
- MXTraceMsg(1, "**> Big ReTransCount %d for LNN %d\n",
- FP->RetransCount, HOTS->LNN);
- (void) MMUpcallHandler[BIGRETRANSCOUNT](HOTS); /* Call higher level
- handler routine */
- };
- };
- }
-
-
- /***********************************************************************/
- HResult TimeoutHandler()
- {
- /* Check for timeouts. */
- TimerId dummy;
-
- MXTraceMsg(4, "TimeoutHandler checking nodes:\n");
-
- for (HOTS = THead.TNext; HOTS != &THead; HOTS = HOTS->TNext) {
-
- MXTraceMsg(4, "LNN %4d AckCount= %4d MsgCount= %4d\n",
- HOTS->LNN, HOTS->AckTimerCount, HOTS->MsgTimerCount);
-
- /* The following code allows the MsgTimerCount to be left
- * uncancelled: It will be cancelled at Timeout time instead.
- */
- if ( HOTS->MsgTimerCount > 0 && --HOTS->MsgTimerCount == 0 ) {
- MsgTimeout();
- } else if ( HOTS->SentPtr == NULLFP ) HOTS->MsgTimerCount = 0;
-
- if ( HOTS->AckTimerCount > 0 && --HOTS->AckTimerCount == 0) {
- AckTimeout();
- }
-
- if ( HOTS->MsgTimerCount <= 0 && HOTS->AckTimerCount <= 0 ) {
- /* Dequeue this LNN from timing list. */
- MXTraceMsg(4, "Dropped from timer Q lnn=%d\n", HOTS->LNN);
- HOTS->TNext->TPrev = HOTS->TPrev;
- HOTS->TPrev->TNext = HOTS->TNext;
- HOTS->Timed = FALSE;
- }
- }
-
- /* Reset timer if anyone still wants timeouts. */
- if (TimerActive = (THead.TNext != &THead) )
- MMSetMicroTimer((int)(vMMTickSize/1000000), (int)(vMMTickSize%1000000),
- (HandlerPtr)TimeoutHandler, 0, &dummy);
- }
-
- /***********************************************************************/
- /* SendFrame */
- /* Send a flow-controlled frame out onto the Ethernet. */
- /* The destination node's HOTS entry must be accessible thru HOTS. */
- /***********************************************************************/
- static KKStatus SendFrame(fP)
- FramePtr fP;
- {
- int size, nbytes;
- KKStatus status;
-
- /* Stop ACK timer. */
- MXTraceMsg(4, "ACK Timer stopped.\n");
- HOTS->AckTimerCount = 0;
- HOTS->LatestAck = fP->packet.EnetData.MsgHdr.MsgAck =
- PrvSeq(HOTS->MsgExpected);
- size = MessageHdrSize + fP->packet.EnetData.MsgHdr.MsgSize;
- MXTraceMsg(3, "SendFrame to LNN %d, msg #%d, Ack %d, SNType %d\n",
- HOTS->LNN,
- fP->packet.EnetData.MsgHdr.MsgSeq,
- fP->packet.EnetData.MsgHdr.MsgAck,
- fP->packet.EnetData.MsgHdr.SNType);
- MXTraceMsg(5,
- "sending to: EtherNetAddr: %s, port: %d\n",
- inet_ntoa(HOTS->EtherAddr.sin_addr),
- ntohs((HOTS->EtherAddr).sin_port));
-
- cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
-
- #ifdef BSD
-
- nbytes = sendto( MMEtherFile, &fP->packet, size, 0, &(HOTS->EtherAddr),
- ETHERNETSIZE);
-
- #else
- #ifdef xkernel
- {
- SESSN s;
- PART part[3];
- UDPaddr baz,zip;
-
- baz.port = (HOTS->EtherAddr).sin_port;
- *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
- part[1].address = (char *)&baz;
-
- zip.port = baz.port;
- /* zip.host needs to be assigned here */
- part[0].address = (char *)&zip;
-
- part[2].address = NULL; part[2].length = 0; /* null terminate */
-
- EMXSEND(s,part,&fP->packet,size,nbytes);
- }
- #endif
- #endif
-
- MXTraceMsg(5, "SendFrame: after sendto: nbytes,size,errno = %d,%d,%d\n",
- nbytes, size, (nbytes == -1) ? errno : 0);
-
- if ( nbytes == -1 ) {
- status = mSystemError( errno );
- } else if ( nbytes = size ) {
- status = MMSS_Success;
- } else status = mSystemError(errno);
-
- /* Start timeout timer if necessary. */
- if ( ! HOTS->Timed || HOTS->MsgTimerCount <= 0) {
- HOTS->MsgTimerCount = vMMMsgTimeout;
- CheckTimer;
- };
- return status;
-
- }
-
- /***********************************************************************/
- /* SendSubNetPacket */
- /* Sends a subnet message which circumvents the flow control */
- /* and thus delivers the message directly without any further */
- /* ado except for piggyback ACK. Assumes that HOTS points to */
- /* destination. */
- /***********************************************************************/
-
- /*ARGSUSED*/
- void SendSubNetPacket( fSNType, fmsg)
- SubNetType fSNType;
- MessagePtr fmsg;
- {
- int size, nbytes;
-
- /* Stop ACK timer. */
- MXTraceMsg(4, "ACK Timer stopped.\n");
- HOTS->AckTimerCount = 0;
-
- /* Use the preinitialized packet */
- SNpacket.EnetData.MsgHdr.MsgDest = HOTS->LNN;
- HOTS->LatestAck = SNpacket.EnetData.MsgHdr.MsgAck =
- PrvSeq(HOTS->MsgExpected);
- SNpacket.EnetData.MsgHdr.SNType = fSNType;
- MXTraceMsg(3, "SendSubNetPacket SNtype %d, destLNN %d, MsgAck %d\n",
- fSNType, SNpacket.EnetData.MsgHdr.MsgDest,
- SNpacket.EnetData.MsgHdr.MsgAck);
- /* Note, for now fmsg MUST be NULL */
-
- size = MessageHdrSize /* + fmsg size */;
- MXTraceMsg(5, "SendSubNetPacket: ethaddr in HOTS->EtherAddr = %s\n",
- inet_ntoa(HOTS->EtherAddr.sin_addr));
- MXTraceMsg(5, "SendSubNetPacket: (HOTS->EtherAddr).sin_port = %d\n",
- ntohs((HOTS->EtherAddr).sin_port));
- cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
-
- #ifdef BSD
-
- nbytes = sendto( MMEtherFile, &SNpacket, size, 0, &(HOTS->EtherAddr),
- ETHERNETSIZE);
-
- #else
- #ifdef xkernel
- {
- SESSN s;
- PART part[3];
- UDPaddr baz,zip;
-
- baz.port = (HOTS->EtherAddr).sin_port;
- *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
- part[1].address = (char *)&baz;
-
- zip.port = baz.port; /*?*/
- /* zip.host needs assigning here */
- part[0].address = (char *)&zip;
-
- part[2].address = NULL; part[2].length = 0;
-
- EMXSEND(s,part,&SNpacket,size,nbytes);
- }
- #endif
- #endif
-
- MXTraceMsg(5, "SendSubNetPacket: after sendto: nbytes, size = %d, %d\n",
- nbytes, size);
- if ( nbytes == -1 ) {
- MXTraceMsg(1, "SendSubNetPacket: error #%d\n", errno);
- }
- }
-
-
- /************************************************************************/
- /* */
- /* Assign a message number. */
- /* */
- /************************************************************************/
-
- static void AssignMsgId(/* returns */ fMsgId
- )
- MessageId *fMsgId;
- {
-
- *fMsgId = ( MMLocalLNN << 16 ) + MMNextMsgId;
- MMNextMsgId = ( (MMNextMsgId == MAXMSGID) ? FIRSTMSGID : (MMNextMsgId+1) );
-
- MXTraceMsg(6, "Message id %08x allocated\n", *fMsgId);
- }
-
- /***********************************************************************/
-
- static KKStatus InitEthernet(fPort)
- int fPort; /* Port number for broadcasts */
- {
- struct hostent *hp;
- char myName[MAXHOSTNAMELENGTH];
- KKStatus lStatus;
- #ifndef xkernel
- int on = 1;
- struct ifreq ifr;
- int s;
- struct sockaddr_in *sin;
- #endif
-
- lStatus = MMSS_Success;
-
- #ifdef BSD
- /* Create network UDP socket */
-
- if ((MMEtherFile = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- return mSystemError(errno);
-
-
- /* Bind a name to the socket so other Unix processes can refer to it. */
-
- MMBroadcastPort = fPort;
- MMBroadcastAddr.sin_port = MMLocalEtherNet.sin_port = MMBroadcastPort;
- MMBroadcastAddr.sin_family = MMLocalEtherNet.sin_family = AF_INET;
-
- if (bind(MMEtherFile, &MMLocalEtherNet, ETHERNETSIZE) < 0) {
- #ifdef MULTIPLEKERNELS
- if (errno == EADDRINUSE) {
- /* If the broadcaqst Port is already in use
- (e.g. by the Eden Kernel broadcast
- process), take any port */
- MXTraceMsg(1,"%s service port already in use...\n", fServiceName);
- MMLocalEtherNet.sin_port = INADDR_ANY;
- if (bind(MMEtherFile, &MMLocalEtherNet, ETHERNETSIZE) < 0 )
- return mSystemError(errno);
- else {
- size = ETHERNETSIZE;
- if (getsockname(MMEtherFile, &MMLocalEtherNet, &size) < 0)
- return mSystemError(errno);
- MXTraceMsg(1,"New port number allocated = %d\n",
- ntohs(MMLocalEtherNet.sin_port));
- lStatus = MMSS_ServPortTaken;
- }
- }
- else
- #endif MULTIPLEKERNELS
- return mSystemError(errno);
- }
- #else
- #ifdef xkernel
- {
- PART part[3];
- UDPaddr foo,bar;
-
- xcontrolprotl(IP,MYADDR,(char *)&myipaddr,IPADLEN);
-
- /* initialize part[0] to me */
- MMBroadcastPort = fPort;
- foo.port = MMLocalEtherNet.sin_port = fPort;
- foo.host = myipaddr;
- part[0].length = sizeof(foo) ;
- part[0].address = (char *)&foo;
-
- /* initialize part[1] to any */
- bar.host = myipaddr;
- xcontrolprotl(IP,MYNET,(char *)&(bar.host),IPADLEN);
- bar.port = foo.port;
- part[1].length = sizeof(bar);
- part[1].address = (char *)&bar;
-
- part[2].address = NULL; part[2].length = 0; /* null terminate */
-
- if(xopenenable(MMEtherProtl,UDP,part)== -1)
- MXTraceMsg(3, "Can't openenable UDP in msgCode.c!");
- }
- #endif
- #endif
-
- /* Find out Ethernet address of this machine, and fill in the appropriate
- fields in MMLocalEtherNet */
-
- if (gethostname(myName, MAXHOSTNAMELENGTH - 1) < 0)
- return mSystemError(errno);
- MXTraceMsg(5, "My hostname is %s\n", myName);
- hp = gethostbyname(myName);
- if (hp == NULL)
- return mSystemError(errno);
- COPYADDR(hp->h_addr, &(MMLocalEtherNet.sin_addr.s_addr),
- hp->h_length);
-
-
- /*++BRDADDR++*/
- #ifndef SIOCGIFBRDADDR
- /* Assume 4.2 non-subnet broadcast, see <netinet/in.h> for IN_* macros */
- COPYADDR(hp->h_addr, &s, hp->h_length);
- s = ntohl(s);
- if ( IN_CLASSA(s) )
- s &= IN_CLASSA_NET;
- else
- if ( IN_CLASSB(s) )
- s &= IN_CLASSB_NET;
- else
- s &= IN_CLASSC_NET;
- MMBroadcastAddr.sin_addr.s_addr = htonl(s);
- #else
- /*
- * Get broadcast addr from interface.
- * Good luck! If problems see ifconfig(8) call in
- * /etc/rc* files on your local host.
- */
- #ifdef xkernel
- {
- IPaddr bar;
-
- MMBroadcastPort = fPort;
- bar = myipaddr;
- xcontrolprotl(IP,MYNET,(char *)&bar,IPADLEN);
-
- *(IPaddr *)&MMBroadcastAddr.sin_addr.s_addr = bar;
- }
- #else
- #ifdef BSD
-
- s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-
- if ( s < 0 ) {
- ErrMsg("InitEthernet: can't create tmp socket.\n");
- perror("InitEthernet");
- exit(1);
- }
- /*
- * >>>> WARNING <<<<<
- * Need real interface name here. What to do if
- * multiple interfaces?
- * Wally (VAX 11/750, Unix 4.2bsd) uses il0
- * Roskilde (MicroVAX II, Ultrix) uses qe0
- * Whistler (VAXStar) uses se0
- * June (8550?) uses ni0 (or is it bvpni0?)
- * Megaron (University of Arizona, VAX 8600) uses de0.
- * Diku (DIKU, Copenhagen, Denmark) uses ex0.
- * Thor (DIKU, Copenhagen, Denmark) uses ex0.
- * If the label ETHERDEV is defined then it is used.
- */
-
- #ifdef sun
- #define ETHERDEV "ie0"
- #endif
-
- #if defined(vax) && defined(ARIZONA)
- #define ETHERDEV "de0"
- #endif
-
- #ifdef ETHERDEV
- (void) strcpy(ifr.ifr_name, ETHERDEV);
- #else ETHERDEV
- if (!strcmp(myName, "freja.diku.dk")) {
- (void) strcpy(ifr.ifr_name, "ex0");
- } else if (!strcmp(myName, "freja")) {
- (void) strcpy(ifr.ifr_name, "ex0");
- } else if (!strcmp(myName, "thor.diku.dk")) {
- (void) strcpy(ifr.ifr_name, "ex0");
- } else if (!strcmp(myName, "roar.diku.dk")) {
- (void) strcpy(ifr.ifr_name, "se0");
- } else if (!strcmp(myName, "regnar.diku.dk")) {
- (void) strcpy(ifr.ifr_name, "es0");
- } else if (!strcmp(myName, "bjarke.diku.dk")) {
- (void) strcpy(ifr.ifr_name, "se0");
- } else if (!strcmp(myName, "whistler")) {
- (void) strcpy(ifr.ifr_name,"se0");
- } else if (!strcmp(myName, "uw-june")) {
- (void) strcpy(ifr.ifr_name,"ni0");
- } else if (!strcmp(myName, "june")) {
- (void) strcpy(ifr.ifr_name,"ni0");
- } else {
- #if defined(vax)
- (void) strcpy(ifr.ifr_name,"qe0");
- #endif
- #if defined(sun)
- (void) strcpy(ifr.ifr_name,"ec0");
- #endif
- }
-
- #endif ETHERDEV
-
- if (strcmp(&vMMEtherDevName[0], "") != 0) {
- MXTraceMsg(2, " Ethernet device: %s\n", ifr.ifr_name);
- strcpy(ifr.ifr_name, &vMMEtherDevName[0]);
- }
-
-
- MXTraceMsg(3, "Ethernet device name: %s\n", ifr.ifr_name);
-
- if ( ioctl(s, (int) SIOCGIFBRDADDR, (caddr_t) &ifr) < 0 ) {
- ErrMsg("InitEthernet: cannot get broadcast address...\n");
- perror("ioctl");
- abort();
- }
- sin = (struct sockaddr_in *) (&ifr.ifr_addr);
- MMBroadcastAddr.sin_addr.s_addr = sin->sin_addr.s_addr;
- (void) close( s );
-
- #endif BSD
- #endif xkernel
- #endif SIOCGIFBRDADDR
- /*--BRDADDR--*/
-
- MXTraceMsg(5, "InitEthernet: &MMLocalEtherNet : %d\n", &MMLocalEtherNet);
- MXTraceMsg(3, "InitEthernet: MMLocalEtherNet.sin_port : %d\n",
- ntohs(MMLocalEtherNet.sin_port));
- MXTraceMsg(3, "InitEthernet: EtherNetAddress of MMLocalEtherNet : %s\n",
- inet_ntoa(MMLocalEtherNet.sin_addr));
- MXTraceMsg(3, " Broadcast address: %s.\n",
- inet_ntoa(MMBroadcastAddr.sin_addr));
-
- /* Set up socket for non-blocking, asynchronous operation */
-
- #ifdef BSD
- /* FASYNC says send SIGIO, FNDELAY says do not block */
- if (fcntl(MMEtherFile, F_SETFL, FASYNC | FNDELAY) < 0)
- return mSystemError(errno);
-
- /* The following tells which process is to get the SIGIO */
- if (fcntl(MMEtherFile, F_SETOWN, getpid()) < 0)
- return mSystemError(errno);
- #endif
- #ifdef SO_BROADCAST
-
- #ifdef BSD
-
- if( setsockopt(MMEtherFile, SOL_SOCKET, SO_BROADCAST,
- (int) &on, sizeof(on))
- ) return mSystemError(errno);
- #else
- #ifdef xkernel
- /* what on earth goes here?! */
- #endif
- #endif
- #endif
-
- /* Associate handler with socket I/O completion signal for asynchronous
- network communication */
-
- #ifdef BSD
- SISetSockHandler(MMEtherFile, SIREAD, (SIHandlerPtr) MMEthernetInterrupt);
- #endif
- return lStatus;
- }
-
- /*
- * SendOutMsg
- * Send out a msg over the ethernet.
- * It is important that the BroadcastMask field be set correctly for
- * those msgs going over the ether.
- */
- #ifdef xkernel
- /*ARGSUSED*/
- #endif
- KKStatus SendOutMsg(fmsg, faddr )
- MessagePtr fmsg; /* Msg to send */
- DeviceAddr *faddr; /* Dest, if broadcast */
- {
- KKStatus status;
- int size, nbytes, DestLNN, framelength;
- register FramePtr FP;
- EnetPacket packet;
- MessageHeaderPtr hdr;
-
- cMMMsgSentCount++; cMMAccumMsgSize += fmsg->MsgHdr.MsgSize;
-
- MXTraceMsg(3, "Send MsgId %06x, SNType %d, to LNN %d, MsgType 0x%06x, Subtype 0x%06x\n",
- fmsg->MsgHdr.MsgId, fmsg->MsgHdr.SNType, fmsg->MsgHdr.MsgDest,
- fmsg->MsgHdr.MsgType, fmsg->MsgHdr.MsgSubtype);
-
- if ( (fmsg->MsgHdr.SNType == SNBROADCAST) ) {
- /* Send out non-flow controlled (broadcast) packet directly */
- MXTraceMsg(5, "BROADCAST\n");
- packet.EnetData.MsgHdr = fmsg->MsgHdr;
- packet.EnetData.MsgHdr.SrcSinPort = MMLocalEtherNet.sin_port;
- packet.EnetData.MsgHdr.SrcSinAddr = MMLocalEtherNet.sin_addr;
- packet.EnetData.MsgHdr.SrcIncarnationId = nodeIncarnationId;
- bcopy((char *) fmsg->MsgData, (char *) packet.EnetData.MsgData,
- (int)fmsg->MsgHdr.MsgSize);
- size = MessageHdrSize + fmsg->MsgHdr.MsgSize;
- cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
-
- #ifdef BSD
-
- nbytes = sendto( MMEtherFile, &packet, size, 0, &(faddr->DeviceEnet),
- ETHERNETSIZE);
-
- #else
- #ifdef xkernel
- {
- SESSN s;
- PART part[3];
- UDPaddr baz,zip;
-
- baz.port = MMBroadcastPort;
- baz.host = myipaddr;
- xcontrolprotl(IP,MYNET,(char *)&(baz.host),IPADLEN);
- part[1].address = (char *)&baz;
-
- zip.port = baz.port;
- /* zip.host gets?? */
- part[0].address = (char *)&zip;
-
- part[2].address = NULL; part[2].length = 0; /* null terminate */
-
- EMXSEND(s,part,&packet,size,nbytes);
- }
- #endif
- #endif
-
- MXTraceMsg(4, "SendOutMsg: bcast, sendto: size,nbytes,errno = %d,%d,%d\n",
- size, nbytes, (nbytes < 0 ? errno : 0) );
- if ( nbytes == -1 )
- status = mSystemError( errno );
- else if ( nbytes = size ) {
- status = MMSS_Success;
- } else status = mSystemError(errno);
- } else if ( (fmsg->MsgHdr.SNType != SNNORMAL) ) {
- /* Send out non-flow controlled (raw) packet directly */
- DestLNN = fmsg->MsgHdr.MsgDest;
- MXTraceMsg(5, "SendOutMsg RAW msg to LNN %d\n", DestLNN);
-
- packet.EnetData.MsgHdr = fmsg->MsgHdr;
- packet.EnetData.MsgHdr.SrcSinPort = MMLocalEtherNet.sin_port;
- packet.EnetData.MsgHdr.SrcSinAddr = MMLocalEtherNet.sin_addr;
- packet.EnetData.MsgHdr.SrcIncarnationId = nodeIncarnationId;
- bcopy((char *) fmsg->MsgData, (char *) packet.EnetData.MsgData,
- (int)fmsg->MsgHdr.MsgSize);
-
- /* Call higher level routine to search HOTS table */
- status = MMUpcallHandler[HOTSSEARCHPTR](DestLNN, &HOTS);
-
- /* Note, HOTS is global within this module. */
- if (! mSUCCESS(status)) return MMSF_BadNode;
- if (HOTS->NodeStat == Dead) return MMSF_NodeDown;
-
- size = MessageHdrSize + fmsg->MsgHdr.MsgSize;
- cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
-
- #ifdef BSD
-
- nbytes = sendto( MMEtherFile, &packet, size, 0, &(HOTS->EtherAddr),
- ETHERNETSIZE);
-
- #else
- #ifdef xkernel
- {
- SESSN s;
- PART part[3];
- UDPaddr baz,zip;
-
- baz.port = (HOTS->EtherAddr).sin_port;
- *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
- part[1].address = (char *)&baz;
-
- zip.port = baz.port;
- /* zip.host = ?? */
- part[0].address = (char *)&zip;
-
- part[2].address = NULL; part[2].length = 0;
-
- EMXSEND(s,part,&packet,size,nbytes);
- }
- #endif
- #endif
-
- MXTraceMsg(4, "SendOutMsg: sendto: size,nbytes,errno = %d,%d,%d\n",
- size, nbytes, (nbytes < 0 ? errno : 0) );
- if ( nbytes == -1 )
- status = mSystemError( errno );
- else if ( nbytes = size ) {
- status = MMSS_Success;
- } else status = mSystemError(errno);
- } else {
- /* SNNORMAL message subnet type, flow-controlled */
- DestLNN = fmsg->MsgHdr.MsgDest;
- MXTraceMsg(5, "SendOutMsg flow controlled msg to LNN %d\n", DestLNN);
-
- /* Call higher level routine to search HOTS table */
- status = MMUpcallHandler[HOTSSEARCHPTR](DestLNN, &HOTS);
-
- /* Note, HOTS is global within this module. */
- if (! mSUCCESS(status)) return MMSF_BadNode;
- if (HOTS->NodeStat == Dead) return MMSF_NodeDown;
-
- /* Copy message into a frame. */
- framelength = sizeof(Frame) + fmsg->MsgHdr.MsgSize - MAXMESSAGESIZE;
- MXTraceMsg(6, "Allocating frame, size= %d, msgsize= %d\n",
- framelength, fmsg->MsgHdr.MsgSize);
-
- FP = (FramePtr) malloc ((unsigned)framelength);
-
- MXTraceMsg(6, "Frame alloc (size = %d) returned %08x\n",
- framelength, FP);
-
- if (FP == NULL) return MMSK_NoMem;
- FP->RetransCount = 0;
- hdr = &FP->packet.EnetData.MsgHdr;
- FP->packet.EnetData.MsgHdr = fmsg->MsgHdr;
-
- bcopy((char *) fmsg->MsgData, (char *) FP->packet.EnetData.MsgData,
- (int)fmsg->MsgHdr.MsgSize);
-
- hdr->MsgSeq = HOTS->NextSeqNo;
- IncSeq(HOTS->NextSeqNo);
-
- /* If I have not yet sent a flow-controlled message to this node, use
- SNType SNFIRSTFCMSG */
- if (!(HOTS->FirstFCMsgSent)) {
- MXTraceMsg(2, "SendOutMsg: First flow-controlled message to LNN %d\n",
- HOTS->LNN);
- hdr->SNType = SNFIRSTFCMSG;
- HOTS->FirstFCMsgSent = TRUE;
- }
- else
- hdr->SNType = SNNORMAL;
-
- MXTraceMsg(4, "Msg Id %08x MsgSeq %d FramePtr %08x\n",
- hdr->MsgId, hdr->MsgSeq, FP);
-
- /* Check to see if we may send it. */
- if (HOTS->SendWindowSize < vMMSendWindow) {
- /* Send Frame. */
- HOTS->SendWindowSize++;
- IncSeq(HOTS->NextMsgToSend);
- MXTraceMsg(6, "Sending frame.\n");
- QueueIns(HOTS->SentPtr, FP, Next);
- status = SendFrame(FP);
- MXTraceMsg(6, "SendOutMsg: after SendFrame, status = %d\n",status);
-
- } else {
- /* Queue for later transmission. */
- if ( MMTrace ) {
- MXTraceMsg(3,
- "Send window overflow, msg seq. deferred: %d\n",
- hdr->MsgSeq);
- MXTraceMsg(5,
- "Send window size %d\n", HOTS->SendWindowSize);
- };
- QueueIns(HOTS->ToSendPtr, FP, Next);
- /* upcall for message deferred */
- MMUpcallHandler[SENDWINDOWFULL](HOTS);
- status = MMSS_Success;
- }
- }
- return status;
- }
-
-
- /************************************************************/
- /* */
- /* MMDefineDimension */
- /* */
- /* MMDefineDimension is an undocumented procedure which */
- /* changes the EDENMSG constant used in ethernet packet */
- /* headers. It is useful for running test versions of */
- /* the message module or in applications which do not want */
- /* to interfere with Eden Kernel communication. */
- /* Use this call with a dimension number between 0 and 5 */
- /* (0 is default and is used by normal Eden Kernels.) */
- /* BEFORE calling MMInitMsgModule. Processes using dimension*/
- /* N will only be able to communicate with other dimension */
- /* N processes over the ethernet. IPC messages do not use */
- /* this dimension number so it has no effect on them. Note */
- /* that changes could be made to have the same effect on */
- /* IPC messages if needed. */
- /* Users of this call should be sure they know what they */
- /* are doing. */
- /************************************************************/
-
- /* NONFUNCTIONAL since version 3.0 */
- KKStatus MMDefineDimension (fDimension)
- int fDimension;
- {
- MXTraceMsg(4, "MMDefineDimension ( %d )\n", fDimension);
- if (fDimension > 5 || fDimension < 0)
- return (MMSF_BadConfig);
- /* EdenMsgK = EDENMSG - fDimension; */
- return (MMSS_Success);
- }
-
- /************************************************************/
- /* */
- /* MMMaxMsgBytes */
- /* */
- /* MMMaxMsgBytes returns the maximum number of user */
- /* defined data bytes within a message. When using this */
- /* function for determining invocation message size, */
- /* remember this does not include the Escii overhead. */
- /************************************************************/
-
- int MMMaxMsgBytes ()
- {
- return MAXMESSAGESIZE;
- }
-
- /************************************************************/
- /* */
- /* MMInitMsgModule */
- /* */
- /* MMInitMsgModule initializes all Message Module data */
- /* structures and configures itself based on the supplied */
- /* parameters. If fAsynchronous is True, MMInitMsgModule */
- /* defines the events required to process asynchronous */
- /* interrupts. If fNetPort is True, communication with */
- /* the Ethernet is initialized. MMInitMsgModule must be */
- /* called before accessing any Message Module primitives. */
- /* NOTE: Does NOT initialize anything in the protocol */
- /* managers part of the HOTS table. */
- /* */
- /* Possible status codes: */
- /* MMSS_Success, MMSF_BadConfig, MMSF_Enetx. */
- /* */
- /************************************************************/
-
- KKStatus MMInitMsgModule( fPort )
- int fPort;
-
- {
- KKStatus status;
- HOTSRecord *info;
-
- #ifdef xkernel
- MMEtherProtl = xcreateprotl(MMdemux_handler,
- MMopendone_handler,
- MMclosedone_handler);
- #endif
-
- MXTraceMsg(3,
- "MMInitMsgModule, * $Header: /usr/em/Kernel/MsgOps/RCS/msgCode.v Revision 5.0 86/05/28 08:27:00 eric Exp$ ( %d )\n",
- ntohs((unsigned short)fPort));
-
- status = MMSS_Success;
-
- /* Initialize Message Module globals */
-
- MMLocalLNN = GetLNN();
- MMNextMsgId = FIRSTMSGID;
- MMNetPort = NULLEDENPORT;
- MMInitTimer();
- (void) MMDefineMsgHandler( NULLMSGTYPE, NULLMSGSUBTYPE, (HandlerPtr)NULL,
- (HandlerPtr *)NULL );
-
- /* Initialize this logical nodes network port and */
- /* Ethernet interface for network environment. */
-
- {
-
- MMNetPort = 1; /* Hack to let it be > 0, Eric Jul, April 1986 */
- status = MMSS_Success;
- if ( mSUCCESS(status) )
- {
- status = InitEthernet(fPort);
- MXTraceMsg(5, "After InitEthernet status = %08x\n", status);
- if ( mSUCCESS(status) )
- {
- /* Make upcall to locate the LNN in the HOTS table */
- if ( mSUCCESS(MMUpcallHandler[HOTSSEARCHPTR]( MMLocalLNN,
- &info )) )
- {
- info->NodeNetPort = MMNetPort;
- mEtherCopy( &(MMLocalEtherNet), &(info->EtherAddr) );
- }
- }
- else return(status);
- }
- }
-
- THead.TPrev = THead.TNext = &THead;
- TimerActive = FALSE;
- MMBuildMsg(&SNpacket.EnetData, NULLMSGTYPE, NULLMSGID, 0, 0);
-
- KMDSetSnap(EtherStats); /* Define snapshot procedure to KMD */
- KMDSetSnap(MMStats);
-
- /* For more information, see notes where the vMM* variables are defined */
- assert(vMMTickSize > 0);
- assert(vMMSendWindow > 0);
- assert(2*vMMSendWindow + 1 < SEQRANGE);
- assert(vMMACKTimeout < vMMMsgTimeout);
-
- /* Now a few silly outputs to satisfy a messedup kernel programmer.
- Remove at any time. */
- MXTraceMsg(8, "HOTS Record Size = %d\n", sizeof(HOTSRecord));
- MXTraceMsg(8, "EnetPacket size = %d\n", sizeof(EnetPacket));
- MXTraceMsg(8, "MsgHdr size = %d\n", sizeof(MessageHeader));
- assert(sizeof(MessageHeader) == 48);
- return status;
- }
-
-
- /***********************************************************************/
- /* */
- /* MMInitHOTSEntry, MMInitHOTSLNN */
- /* */
- /* Procedures to be called to initialize the HOTS table entry for a */
- /* logical node. MMInitHOTSLNN initializes the entry given the LNN */
- /* while MMInitHOTSEntry takes the pointer to the HOTS entry */
- /***********************************************************************/
-
- void MMInitHOTSEntry(fHOTS)
- register HOTSRecord *fHOTS;
- {
- MXTraceMsg(5, "MMInitHOTSEntry for LNN %d\n", fHOTS->LNN);
- fHOTS->ToSendPtr = NULLFP;
- fHOTS->SentPtr = NULLFP;
- MMInitList(fHOTS->RecvPtr);
- fHOTS->AckExpected = 0;
- fHOTS->NextMsgToSend = 0;
- fHOTS->NextSeqNo = 0;
- fHOTS->TooFar = vMMSendWindow;
- fHOTS->MsgExpected = 0;
- fHOTS->LatestAck = PrvSeq(fHOTS->MsgExpected);
- fHOTS->SendWindowSize = 0;
- fHOTS->OutOfOrderCount = 0;
- fHOTS->Timed = FALSE;
- fHOTS->AckTimerCount = 0;
- fHOTS->MsgTimerCount = 0;
- fHOTS->TNext = fHOTS;
- fHOTS->TPrev = fHOTS;
- fHOTS->NakSent = FALSE;
- fHOTS->FirstFCMsgSent = FALSE;
- fHOTS->RetransCount = 0;
- fHOTS->NAKsSent = fHOTS->NAKsRecv = fHOTS->MsgDropped = 0;
- fHOTS->ACKsSent = fHOTS->ACKsRecv = 0;
- fHOTS->MsgDelivered = fHOTS->MsgAccepted = 0;
- }
-
- KKStatus MMInitHOTSLNN(fLNN)
- NodeNum fLNN;
- {
- HOTSRecord *HOTSPtr;
- KKStatus status;
-
- MXTraceMsg(4, "MMInitHOTSLNN for LNN %d\n", fLNN);
-
- /* Call higher level routine to search HOTS table */
- status = MMUpcallHandler[HOTSSEARCHPTR](fLNN, &HOTSPtr);
-
- if ( ! mSUCCESS(status) ) return status;
-
- MMInitHOTSEntry(HOTSPtr);
- return MMSS_Success;
- }
-
- void MMRemoteNodeDeath(fHOTS)
- register HOTSRecord *fHOTS;
- /* This routine will cleanup all field that concern the
- sliding window protocol.
- This includes dropping the entry from timeout queues,
- discarding and deallocating pending messages, and
- resetting all fields to an initial value.
- NB: This routine updates the timer queues and calls
- free.
- */
- {
- register FramePtr FP;
-
- /* Called to clean up when a node dies. */
- DebugMsg(4, "MMRemoteNodeDeath: LNN = %d\n", fHOTS->LNN);
- MXTraceMsg(2, "MMRemoteNodeDeath: LNN = %d\n", fHOTS->LNN);
-
- if (fHOTS->Timed) {
- MXTraceMsg(4, "Removing from timing queue.\n");
- fHOTS->TNext->TPrev = fHOTS->TPrev;
- fHOTS->TPrev->TNext = fHOTS->TNext;
- fHOTS->Timed = FALSE;
- };
-
- /* Drop old messages from queues. */
- while (fHOTS->SentPtr != NULL) {
- QueueRmv(fHOTS->SentPtr, FP, Next);
- MXTraceMsg(2, "Discarding unacked msg seq. %d\n",
- FP->packet.EnetData.MsgHdr.MsgSeq);
- MXTraceMsg(2, "MsgId 0%06x, MsgType 0x%02x, Subtype 0x%02x\n",
- FP->packet.EnetData.MsgHdr.MsgId,
- FP->packet.EnetData.MsgHdr.MsgType,
- FP->packet.EnetData.MsgHdr.MsgSubtype);
- free((char *) FP);
- };
-
- while (fHOTS->ToSendPtr != NULL) {
- QueueRmv(fHOTS->ToSendPtr, FP, Next);
- MXTraceMsg(2, "Discarding unsent msg seq. %d\n",
- FP->packet.EnetData.MsgHdr.MsgSeq);
- MXTraceMsg(2, "MsgId 0%06x, MsgType 0x%02x, Subtype 0x%02x\n",
- FP->packet.EnetData.MsgHdr.MsgId,
- FP->packet.EnetData.MsgHdr.MsgType,
- FP->packet.EnetData.MsgHdr.MsgSubtype);
- free((char *) FP);
- };
-
- MXTraceMsg(3, "End MMRemoteNodeDeath\n");
-
- /* Reinitialize the sliding window protocol fields. */
- MMInitHOTSEntry(fHOTS);
- }
-
- /************************************************************/
- /* */
- /* MMAllocateMsg */
- /* */
- /* MMAllocateMsg allocates a contiguous message buffer of */
- /* fSize bytes (plus a header). */
- /* Buffer management is done by Guy Almes version of */
- /* malloc tuned to be optimal for message sizes. */
- /* If message sizes grow beyond 2044, malloc should be */
- /* retuned. */
- /* */
- /* Possible status codes: */
- /* MMSS_Success, MMSK_NoMem, MMSF_MsgOvfl */
- /* */
- /************************************************************/
-
- KKStatus MMAllocateMsg( fSize, /* Data Size (in bytes) */
- /* returns */ fMsg /* Message Buffer */
- )
- int fSize;
- MessagePtr *fMsg;
- {
- register MessagePtr newmsg;
- register MessageHeaderPtr hdr;
-
- MXTraceMsg(5, "MMAllocateMsg( %d )\n", fSize);
-
- if ( ((unsigned int) fSize) > MAXMESSAGESIZE )
- return MMSF_MsgOvfl;
-
- newmsg = (MessagePtr) malloc( (unsigned) (fSize+MessageHdrSize) );
-
- if ( newmsg == NULL )
- return MMSK_NoMem;
- hdr = &newmsg->MsgHdr;
- hdr->MsgVersion = VER_MsgModule;
- hdr->MsgSize = fSize;
- hdr->MsgSrc = MMLocalLNN;
- hdr->SrcSinPort = MMLocalEtherNet.sin_port;
- hdr->SrcSinAddr = MMLocalEtherNet.sin_addr;
- hdr->SrcIncarnationId = nodeIncarnationId;
-
- *fMsg = newmsg;
-
- cMMMsgAllocCount++;
-
- MXTraceMsg(6, "new msg address %d\n", newmsg);
-
- return MMSS_Success;
- }
-
- /************************************************************/
- /* */
- /* MMDeallocateMsg */
- /* */
- /* MMDeallocateMsg releases the buffer storage associated */
- /* with the specified message. See MMAllocateMsg.
- /* */
- /************************************************************/
-
- void MMDeallocateMsg( fMsg /* Message Buffer */
- )
- MessagePtr fMsg;
- {
- MXTraceMsg(5, "MMDeallocateMsg(0x%06x)\n", fMsg);
-
- if ( fMsg != NULL ) {
- free( (char *) fMsg );
- cMMMsgDeAllocCount++;
- }
- MXTraceMsg(6, "MMDeallocateMsg returns\n");
- }
-
- /************************************************************/
- /* */
- /* MMBuildMsg */
- /* */
- /* MMBuildMsg initializes the header of the specified */
- /* message buffer with the user-defined attributes. The */
- /* message source logical node number is automatically set */
- /* to the users logical node number. The message number */
- /* is not assigned until MMSendMsg is called. */
- /* */
- /* Possible status codes: */
- /* MMSS_Success, MMSF_MsgOvfl */
- /* */
- /************************************************************/
-
- void MMBuildMsg( fMsg, /* Message Buffer */
- fType, /* Message Type */
- fSubtype, /* Message Subtype */
- fDestination, /* Destination LNN */
- fSize /* Message Data Size */
- ) /* (in bytes) */
- register MessagePtr fMsg;
- MessageType fType;
- MessageSubtype fSubtype;
- NodeNum fDestination;
- unsigned int fSize;
- {
- register MessageHeaderPtr hdr;
-
- MXTraceMsg(5, "MMBuildMsg( %d, 0x%08x, 0x%08x, %d, %d )\n", fMsg, fType,
- fSubtype, fDestination, fSize);
-
- hdr = &fMsg->MsgHdr;
- hdr->MsgVersion = VER_MsgModule;
- hdr->MsgSrcPort = NULLEDENPORT;
- hdr->MsgSrc = MMLocalLNN;
- hdr->MsgDestPort = NULLEDENPORT;
- hdr->MsgDest = fDestination;
- hdr->MsgType = fType;
- hdr->MsgSubtype = fSubtype;
- hdr->MsgSize = fSize;
- hdr->SrcSinPort = MMLocalEtherNet.sin_port;
- hdr->SrcSinAddr = MMLocalEtherNet.sin_addr;
- hdr->SrcIncarnationId = nodeIncarnationId;
-
- return;
- }
-
- /************************************************************/
- /* */
- /* MMSendMsg */
- /* */
- /* Send out a message. */
- /* */
- /* Possible status codes: */
- /* MMSS_Success, MMSK_NoMem, MMSF_MsgOvfl, MMSF_BadNode,*/
- /* MMSF_NodeDown */
- /* */
- /************************************************************/
-
- KKStatus MMSendMsg( fMsg )
- MessagePtr fMsg; /* Message Buffer */
- {
- DeviceAddr addr;
- KKStatus status;
-
- MXTraceMsg(4, "MMSendMsg(0x%06x) to node %d\n", fMsg, fMsg->MsgHdr.MsgDest);
-
- if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
- return MMSF_MsgOvfl;
-
- if (fMsg->MsgHdr.MsgDest == GetLNN())
- return MMSF_BadNode;
-
- AssignMsgId (&fMsg->MsgHdr.MsgId);
- fMsg->MsgHdr.BroadcastMask = NULLNODE;
- fMsg->MsgHdr.SNType = SNNORMAL;
-
- cMMMsgSentSynchCount++;
-
- status = SendOutMsg(fMsg, &addr);
- return status;
- }
-
- KKStatus MMSendRawMsg( fMsg )
- MessagePtr fMsg; /* Message Buffer */
- {
- DeviceAddr addr;
- KKStatus status;
-
- MXTraceMsg(4, "MMSendRawMsg(0x%06x) to node %d\n", fMsg,
- fMsg->MsgHdr.MsgDest);
-
- if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
- return MMSF_MsgOvfl;
-
- if (fMsg->MsgHdr.MsgDest == GetLNN())
- return MMSF_BadNode;
-
- AssignMsgId (&fMsg->MsgHdr.MsgId);
- fMsg->MsgHdr.BroadcastMask = NULLNODE;
- fMsg->MsgHdr.SNType = SNRAWMSG;
-
- cMMMsgSentRawCount++;
-
- status = SendOutMsg(fMsg, &addr);
- return status;
- }
-
- /************************************************************/
- /* */
- /* MMBroadcastMsg */
- /* */
- /* MMBroadcastMsg is the standard primitive for transmitting*/
- /* a message to more than one logical node at a time. It */
- /* disassembles the message, assigns a message number, and */
- /* transmits the message to the target nodes. The assigned*/
- /* message number is returned in fMsgId. fNumNodes */
- /* specifies the number of logical nodes the message is to */
- /* be sent to and must be greater than 0. In this case, */
- /* fNodeList specifies the logical nodes the message is to */
- /* be sent to. If fNumNodes is equal to BROADCAST, the */
- /* message is broadcast to all nodes in the network and the*/
- /* contents of fNodeList is ignored. If fNumNodes is equal*/
- /* to MULTICAST, the message is broadcast to all nodes */
- /* accepting the multicast address contained in fNodeList: */
- /* */
- /* <--- high low ---> */
- /* fNodeList[2] | fNodeList[1] | fNodeList[0] */
- /* */
- /* Broadcast messages are restricted to MAXMESSAGESIZE bytes*/
- /* and reception by any or all of the target nodes is not */
- /* guaranteed. MMBroadcastMsg operates synchronously. */
- /* Control is not returned to the caller until the message */
- /* has been successfully transmitted to all target nodes or*/
- /* an error is detected. */
- /* */
- /* Possible status codes: */
- /* MMSS_Success, MMSF_MsgOvfl, MMSF_NodeDown, MMSF_IPCx,*/
- /* MMSF_Enetx */
- /* */
- /************************************************************/
-
- KKStatus MMBroadcastMsg ( fMsg )
- MessagePtr fMsg; /* Message Buffer*/
- {
- DeviceAddr dest;
-
- MXTraceMsg(3,"MMBroadcastMsg( 0x%08x) MsgType 0x02x, SubType 0x%02x\n",
- fMsg, fMsg->MsgHdr.MsgType, fMsg->MsgHdr.MsgSubtype);
-
- /* The following test should test against the max broadcast size
- which for UNIX 4.2bsd is smaller than MAXMESSAGESIZE */
-
- if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
- return MMSF_MsgOvfl;
-
- AssignMsgId (&fMsg->MsgHdr.MsgId);
-
- {
- dest.DeviceLocal = False;
- dest.DeviceEnet = MMBroadcastAddr;
- MXTraceMsg(5,
- "MMBroadcastMsg: EthAddr in dest.DeviceEnet = %s\n",
- inet_ntoa(dest.DeviceEnet.sin_addr));
- MXTraceMsg(5, "MMBroadcastMsg: dest.DeviceEnet.sin_port = %d\n",
- ntohs(dest.DeviceEnet.sin_port));
- MXTraceMsg(5, "MMBroadcastMsg: dest.DeviceEnet.sin_family = %d\n",
- dest.DeviceEnet.sin_family);
- fMsg->MsgHdr.SNType = SNBROADCAST;
- cMMBroadcastHOSTCount++;
- return (SendOutMsg(fMsg, &dest));
- }
- }
-
- /****************************************************************/
- /* */
- /* MMEthernetInterrupt */
- /* */
- /****************************************************************/
- #ifdef xkernel
- int MMEthernetInterrupt()
- {
- /* we should never get here */
- MXTraceMsg(1, "Should never get here in msgCode.c!\n");
- assert(FALSE);
- }
- #else
- int MMEthernetInterrupt()
- {
- int nbytes;
- MessagePtr newmsg;
- EnetPacket packet;
- register EnetPacketPtr enet;
- KKStatus status;
- struct sockaddr senderAddr;
- int senderAddrSize;
- int count;
-
- count = 0;
- cMMEthernetIntCount++;
- do {
- MXTraceMsg(4, "**** MMEthernetInterrupt: pass %d.\n",++count);
-
- enet = &packet;
- nbytes = recvfrom( MMEtherFile, (char *) enet, sizeof(EnetPacket), 0,
- &senderAddr, &senderAddrSize);
-
- if ( nbytes < 0 ) {
- status = mSystemError( errno );
- if ( status == SYSK_EWOULDBLOCK ) {
- MXTraceMsg(5, "EWOULDBLOCK so no more reading to do.\n");
- status = MMSS_Success;
- break;
- }
- if ( status == SYSK_EINTR ) continue;
- MXTraceMsg(1,"recvfrom error: %08x.\n",status);
- break;
- }
-
- status = MMSS_Success;
- if ( MMTrace ) {
- MXTraceMsg(5, "%d requested, %d bytes read.\n",
- sizeof(EnetPacket), nbytes);
- MXTraceMsg(4,
- "EtherInt> MsgId 0x%06x Seq %d SNType %d SrcLNN %d\n",
- packet.EnetData.MsgHdr.MsgId, packet.EnetData.MsgHdr.MsgSeq,
- packet.EnetData.MsgHdr.SNType, packet.EnetData.MsgHdr.MsgSrc);
- MXTraceMsg(4, "MsgType 0x%06x, MsgSubtype 0x%06x\n",
- packet.EnetData.MsgHdr.MsgType,
- packet.EnetData.MsgHdr.MsgSubtype);
- };
-
- #ifdef DROPTEST
- /* DROPTEST:
- * For debugging: Asks the debugger if the message should be
- * dropped. Input is read and if a "r" is met
- * then the message is retained else if a "d" is met then
- * the message is dropped. The rest of the line is thrown away.
- * The idea of this test is due to the late Bob Bandes.
- */
- {
- char ch, dumpch;
- printf(
- "EtherInt> MsgId 0x%06x Seq %d SNType %d SrcLNN %d\n",
- packet.EnetData.MsgHdr.MsgId, packet.EnetData.MsgHdr.MsgSeq,
- packet.EnetData.MsgHdr.SNType, packet.EnetData.MsgHdr.MsgSrc);
- printf("MsgType 0x%06x, MsgSubtype 0x%06x\n",
- packet.EnetData.MsgHdr.MsgType,
- packet.EnetData.MsgHdr.MsgSubtype);
- printf("$$$$ DROP TEST (type 'd' to drop, 'r' to retain) >");
- (void) fflush(stdout);
- do {
- ch = getchar();
- } while (ch != 'r' && ch != 'd');
- do {dumpch = getchar();} while (dumpch != '\n');
- if (ch == 'd') {
- printf(" Message DROPPED.\n");
- return;
- }
- printf(" Message Retained.\n");
- };
- #endif DROPTEST
-
- /*
- * Ignore our own broadcasts. This is tricky work since
- * we want to be able to detect a duplicate node being booted,
- * and the initial boot messages is sent out as a broadcast.
- * The only thing done with that message, is to send a reply
- * saying "possession is 9/10ths of the law" so the duplicate
- * will trash itself.
- */
- if ( /* This test takes care of the usual case */
- ( enet->EnetData.MsgHdr.MsgSrc != MMLocalLNN ) ||
- /* This test screens out msg from our own incarnation */
- ( enet->EnetData.MsgHdr.SrcIncarnationId != nodeIncarnationId)
- ) {
- if ( enet->EnetData.MsgHdr.MsgVersion == VER_MsgModule ) {
- status = MMAllocateMsg( MAXMESSAGESIZE, &newmsg);
- /* BUG: somehow it happens that the following bcopy causes
- a segmentation fault, so therefore MAXMESSAGESIZE
- as to ensure enough space (brute force), Eric Jul, 1984-06-03,
- should be : enet->EnetData.MsgHdr.MsgSize */
- if ( mSUCCESS(status) ) {
- newmsg->MsgHdr = enet->EnetData.MsgHdr;
- bcopy ((char *)enet->EnetData.MsgData,(char *)newmsg->MsgData,
- (int) enet->EnetData.MsgHdr.MsgSize);
-
- HoldSigs(); /* Protect QueueTask against signals. */
- QueueTask( (HandlerPtr)MMReceiveEtherHandler, newmsg);
- ReleaseSigs();
- }
- else ErrMsg(">> MMEthernetInterrupt got no buffer 0x%02x\n",
- status);
- }
- else
- MXTraceMsg(1, "MMEthernetInterrupt: Incompatible version #.\n");
- } else MXTraceMsg(4, "Dropping own msg (broadcast)\n");
- } while( 1 );
-
- if ( ! mSUCCESS(status) ) {
- DebugMsg(1,"MMEthernetInterrupt Error: 0x%06x.\n",status );
- }
- MXTraceMsg(5, "***** End of MMEthernetInterrupt\n");
- }
- #endif
-
-
- /****************************************************************/
- /* */
- /* MMReceiveEtherHandler */
- /* */
- /* MMReceiveEtherHandler handles an incoming message (from the */
- /* Ether), takes care of flow control & piggybacked ACKs. */
- /* If the message is not out of order, it and any other in- */
- /* order messages are passed to the appropriate handlers by */
- /* dispatching the handlers. */
- /* */
- /****************************************************************/
-
- static HResult MMReceiveEtherHandler(fmsg)
- MessagePtr fmsg;
- {
- KKStatus status;
- int MsgLNN;
- MessagePtr MP;
- MsgSeqType Villain, PiggyBackAck;
- int sendWindowBlockedAtEntry;
-
- register MessageHeaderPtr hdr;
-
- if (fmsg == NULL) return;
-
- hdr = &fmsg->MsgHdr;
- MsgLNN = hdr->MsgSrc;
-
- if ( MMTrace ) {
- MXTraceMsg(3,
- "MMReceiveEtherHandler, MsgId 0x%02x, MsgSeq %d, SNType %d\n",
- hdr->MsgId, hdr->MsgSeq, hdr->SNType);
- MXTraceMsg(3, "SrcLNN %d, MsgType 0x%06x, MsgSubtype 0x%06x\n",
- hdr->MsgSrc, hdr->MsgType, hdr->MsgSubtype);
- MXTraceMsg(5, "SrcSinPort %d, sin_addr: %s, IncarnationId: %.15s\n",
- ntohs(hdr->SrcSinPort), inet_ntoa(*(struct in_addr *)&hdr->SrcSinAddr),
- 4+ctime(&hdr->SrcIncarnationId));
- }
-
- /* Make Upcall to find HOTS entry for MsgLNN; this might insert
- or update the HOTS based on the hostIncarnationId */
- status = MMUpcallHandler[CHECKMSG]( fmsg, &HOTS);
- if (!mSUCCESS(status)) {
- /* Use the NOHOTSEntry Upcall to handle the situation and retry */
- MXTraceMsg(1, "CHECKMSG failed LNN %d, status = 0x%08x\n",
- MsgLNN, status);
- if (!mSUCCESS(status)) {
- MXTraceMsg(1,
- "MMReceiveEtherHandler: Unknown LNN = %d; status = 0x%08x\n",
- fmsg->MsgHdr.MsgSrc, status);
- MXTraceMsg(1, "SrcPort %d, SinAddr %s, Incarnation %.15s\n",
- ntohs(hdr->SrcSinPort),
- inet_ntoa(*(struct in_addr *)&hdr->SrcSinAddr),
- 4+ctime(&hdr->SrcIncarnationId));
- MXTraceMsg(1, "<<< Message Dropped >>>\n");
- MMDeallocateMsg(fmsg);
- return;
- }
- }
-
- if ( (hdr->SNType == SNBROADCAST) ) {
- /* Dispatch it right away. */
- status = MMDispatchMsg( fmsg );
- if ( ! mSUCCESS(status) ) {
- if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText, 0 ))){
- (void) sprintf(ErrorText, "Status 0x%06x", status);
- }
- ErrMsg("Unable to dispatch incoming message:\n%s\n",
- ErrorText );
- MMDeallocateMsg(fmsg);
- }
- return;
- };
-
- if (HOTS->NodeStat == Dead) {
- /* This should not happen since CheckMsg should fix it */
- /* Not found in HOTS, so if it is not a RAW msg then call Upcall
- handler to deal with missing HOTS entry. */
- if (hdr->SNType == SNRAWMSG) { /* Then just dispatch it.*/
- status = MMDispatchMsg( fmsg );
- }
- if ( ! mSUCCESS(status) ) {
- if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText,
- 0 ))) {
- (void) sprintf(ErrorText, "Status 0x%06x", status);
- }
- ErrMsg("Unable to dispatch incoming message:\n%s\n",
- ErrorText );
- MMDeallocateMsg(fmsg);
- }
- return;
- }
-
- sendWindowBlockedAtEntry = (HOTS->SendWindowSize >= vMMSendWindow);
-
- PiggyBackAck = hdr->MsgAck;
-
- MXTraceMsg(5, "MsgExp=%d, Seq=%d, TooFar=%d\n",
- HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar);
-
- switch (hdr->SNType) {
-
- case SNFIRSTFCMSG: /* First flow-ctrld msg received from this LNN */
- MXTraceMsg(2, "First msg from %d of %.15s arrived\n",
- hdr->MsgSrc, 4+ctime(&hdr->SrcIncarnationId));
- cMMFirstFCMsgCount++;
- MMUpcallHandler[FIRSTFCMSGRECEIVED](HOTS, fmsg);
- /* Note: now that the upper layer protocol has been informed that
- we have received the first flow-controlled msg from this LNN,
- continue processing the message like any other SNNORMAL msg: */
-
- case SNNORMAL:
- if (hdr->MsgSeq != HOTS->MsgExpected) {
- /* Out of order message. */
- MXTraceMsg(2, "Msg #%d out of order MsgExp=%d TooFar=%d\n",
- hdr->MsgSeq, HOTS->MsgExpected, HOTS->TooFar);
- if (! HOTS->NakSent ) {
- HOTS->NakSent = TRUE;
- HOTS->NAKsSent++; cMMNAKsSentCount++;
- MXTraceMsg(2, "Sending NAK of msg #%d to LNN %d\n",
- HOTS->MsgExpected, HOTS->LNN);
- SendSubNetPacket(SNNAK, (MessagePtr) NULL);
- }
- if (between(HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar) &&
- /* Retain if not duplicate. */
- (MMEnterInList(HOTS->RecvPtr, hdr->MsgSeq, (integer) fmsg,
- (integer) NULL)
- == MMSS_Success)
- ) {
- MXTraceMsg(2, "Msg queued.\n");
- HOTS->OutOfOrderCount++; cMMOutOfOrderCount ++;
- } else { /* Msg Dropped */
- MXTraceMsg(2,
- "Dropping Msg #%d from LNN %d: Dupl. or irrelevant.\n",
- hdr->MsgSeq, HOTS->LNN);
- HOTS->MsgDropped++; cMMMsgDroppedCount++;
- MMDeallocateMsg(fmsg);
- }
- /* Start ACK timer if necessary. */
- if (!HOTS->AckTimerCount) {
- /* (use float to prevent integer overflow) */
- MXTraceMsg(4, "ACK Timer started: %f microseconds.\n",
- vMMTickSize * (float) vMMACKTimeout);
- HOTS->AckTimerCount = vMMACKTimeout;
- CheckTimer;
- }
- } else {
- register int UnAcked;
- /* Msg was the expected one. */
- MXTraceMsg(4, "Msg was expected, seqno %d\n",
- HOTS->MsgExpected);
- HOTS->NakSent = FALSE;
- MP = fmsg;
- do {
- MXTraceMsg(3, "Msg #%d ACCEPTED, LatestAck %d\n",
- MP->MsgHdr.MsgSeq, HOTS->LatestAck);
- IncSeq(HOTS->MsgExpected);
- IncSeq(HOTS->TooFar);
- HOTS->MsgAccepted++; cMMMsgAcceptedCount++;
- MXTraceMsg(4, "MsgExp=%d, Seq=%d, TooFar=%d\n",
- HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar);
-
- /* Check ACK: If senders Send Window is near full
- then force an ACK. Else start the ACK timer.
- NOTE: UnAcked = # of unACKed msgs PLUS one. */
-
- if ((UnAcked = (int) HOTS->MsgExpected - (int) HOTS->LatestAck) < 0)
- UnAcked = UnAcked + SEQRANGE; /* Wraparound. */
- MXTraceMsg(4, "UnAcked = %d, ForceAck = %d\n",
- UnAcked, vMMForceAck);
- if (UnAcked > vMMForceAck) {
- /* The senders Send Window is filling: Force an
- ACK to allow sender to free buffers and move window. */
- MXTraceMsg(3, "Forcing ACK to LNN %d, LatestAck = %d\n",
- HOTS->LNN, HOTS->LatestAck);
- HOTS->ACKsSent++; cMMACKsSentCount++;
- SendSubNetPacket(SNACK, (MessagePtr) NULL);
- } else { /* Start the ACK timer. */
- if (!HOTS->AckTimerCount) {
- MXTraceMsg(4, "ACK Timer started LNN %d: %d sec.\n",
- HOTS->LNN, vMMTickSize * vMMACKTimeout);
- HOTS->AckTimerCount = vMMACKTimeout;
- CheckTimer;
- }
- }
-
- status = MMDispatchMsg( MP );
-
- if ( ! mSUCCESS(status) ) {
- if(!mSUCCESS(GetEdenMsg( (int) status, TextSize,
- ErrorText, 0 ))) {
- (void) sprintf(ErrorText, "Status 0x%06x", status);
- }
- ErrMsg("Unable to dispatch incoming message:\n%s",
- ErrorText );
- ErrMsg("Msg Id = 0x%06x\n", MP->MsgHdr.MsgId);
- MMDeallocateMsg(MP);
- }
- /* Check for dispatchable messages. */
- } while ((HOTS->OutOfOrderCount) &&
- mSUCCESS(MMGetFromList(HOTS->RecvPtr, HOTS->MsgExpected,
- (int *)&MP, (int *)NULL)));
- }
- endcase /* SNNORMAL */ ;
-
- case SNRAWMSG:
- /* A raw, non-flow controlled message has arrived, dispatch it. */
- MXTraceMsg(3, "Raw, non-flow controlled msg.\n");
- status = MMDispatchMsg( fmsg );
- if ( ! mSUCCESS(status) ) {
- if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText, 0 ))) {
- (void) sprintf(ErrorText, "Status 0x%06x", status);
- }
- ErrMsg("Unable to dispatch incoming message:\n%s\n", ErrorText);
- MMDeallocateMsg(fmsg);
- }
- return; /* No piggy-back ACK */
- /* endcase SNRAWMSG */ ;
-
- case SNNAK:
- HOTS->NAKsRecv++; cMMNAKsRecvCount++;
- Villain = NxtSeq(hdr->MsgAck);
- MXTraceMsg(2, "NAK from LNN %d of msg #%d\n", HOTS->LNN, Villain);
- MXTraceMsg(3, "AckExp=%d, Villain=%d, NextToSend=%d\n",
- HOTS->AckExpected, Villain, HOTS->NextMsgToSend);
- if ( between(HOTS->AckExpected, Villain, HOTS->NextMsgToSend) ) {
- register FramePtr FP, FirstFP;
- /* Retransmit old frame. */
- FirstFP=FP=HOTS->SentPtr;
- do {
- MXTraceMsg(5, "Queue Search, FP= %d (x%06x), Seq=%d\n",
- FP, FP, FP->packet.EnetData.MsgHdr.MsgSeq);
- if (FP->packet.EnetData.MsgHdr.MsgSeq == Villain) {
- MXTraceMsg(2, "NAK causing Retransmit of MsgSeq %d\n",
- FP->packet.EnetData.MsgHdr.MsgSeq);
- (void) SendFrame(FP);
- HOTS->RetransCount++; cMMRetransCount++;
- FP->RetransCount++;
- break;
- }
- FP=FP->Next;
- } while (FP != FirstFP);
- }
- MMDeallocateMsg(fmsg);
-
- endcase /* SNNAK */;
-
- case SNBROADCAST:
- /* Should not happen. */
- MMDeallocateMsg(fmsg);
- return;
- /* endcase; */
-
- default:
- /* Assume ACK. (Piggyback ack already stripped off, so no work.) */
- HOTS->ACKsRecv++; cMMACKsRecvCount++;
- MMDeallocateMsg(fmsg);
- endcase /* Default */;
-
- } /* Switch */;
-
- /* Now utilize the piggybacked acknowledgement. */
- MXTraceMsg(4, "AckExp=%d, PiggyBACK=%d, NextToSend=%d\n",
- HOTS->AckExpected, PiggyBackAck, HOTS->NextMsgToSend);
- while (between(HOTS->AckExpected, PiggyBackAck, HOTS->NextMsgToSend)) {
- register FramePtr FP;
-
- MXTraceMsg(4, "Piggyback ACK = %d\n", PiggyBackAck);
-
- /* Find msg in list (will be first normally) */
- QueueRmv(HOTS->SentPtr, FP, Next);
- while (FP->packet.EnetData.MsgHdr.MsgSeq != HOTS->AckExpected) {
- /* Not it; put at end and try next (note, it has to be there) */
- QueueIns(HOTS->SentPtr, FP, Next);
- MXTraceMsg(5, "Queue search FP= %d(x%06x), Seq= %d\n",
- FP, FP, FP->packet.EnetData.MsgHdr.MsgSeq);
- QueueRmv(HOTS->SentPtr, FP, Next);
- }
-
- /* Found, now free it and move window pointers. */
- IncSeq(HOTS->AckExpected);
- /* Stop Msg Timer if count goes to zero. */
- HOTS->SendWindowSize--;
- HOTS->MsgDelivered++; cMMMsgDeliveredCount++;
- MXTraceMsg(6, "free (%d=x%06x)\n", FP, FP);
- free((char *) FP);
- }
- /* Stop msg timer if no more msgs are outstanding. */
- if (!(HOTS->SendWindowSize)) HOTS->MsgTimerCount = 0;
-
- /* Send queued messages if there are any and the window is not full. */
- MXTraceMsg(5, "SWSize %d, NextMsgToSend %d\n",
- HOTS->SendWindowSize, HOTS->NextMsgToSend);
- while (HOTS->ToSendPtr != NULL && HOTS->SendWindowSize < vMMSendWindow) {
- register FramePtr FP;
- QueueRmv(HOTS->ToSendPtr, FP, Next);
- MXTraceMsg(4, "Sending blocked msg seq %d\n",
- FP->packet.EnetData.MsgHdr.MsgSeq);
- IncSeq(HOTS->NextMsgToSend);
- HOTS->SendWindowSize++;
- QueueIns(HOTS->SentPtr, FP, Next);
- (void) SendFrame(FP);
- }
- if (sendWindowBlockedAtEntry && (HOTS->SendWindowSize < vMMSendWindow))
- MMUpcallHandler[SENDWINDOWNOTFULL](HOTS);
- }
-